package com.molichuxing.framework.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalUnit;
import java.util.Calendar;
import java.util.Date;

/**
 * @create_date: 2019/1/28
 * @name:framework
 **/
public class DateUtil {
    //日期时间格式
	public static final DateTimeFormatter LOCAL_DATE_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    // 日期格式
	public static final DateTimeFormatter LOCAL_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
	// 日期格式
	public static final DateTimeFormatter LOCAL_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
    // 日期格式
	public static final DateTimeFormatter LOCAL_TIME = DateTimeFormatter.ofPattern("HH:mm:ss");

	public static final String[] PARSE_PATTERNS = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyyMMddHHmmss"};

	public static final String[][] WEEK_ARRAYS = { { "MONDAY", "一" }, { "TUESDAY", "二" }, { "WEDNESDAY", "三" },
			{ "THURSDAY", "四" }, { "FRIDAY", "五" }, { "SATURDAY", "六" }, { "SUNDAY", "日" } };


    private DateUtil() {
    }

	/**
	 * Date转换为LocalDateTime.
	 *
	 * @return java.time.LocalDateTime
	 */
	public static LocalDateTime convertDateToLDT(Date date) {
		return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
	}

	/**
	 * LocalDateTime转换为Date.
	 *
	 * @return java.util.Date
	 */
	public static Date convertLDTToDate(LocalDateTime time) {
		return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
	}

	/**
	 * 获取指定日期的毫秒.
	 *
	 * @return java.lang.Long
	 */
	public static Long getMilliByTime(LocalDateTime time) {
		return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
	}

	/**
	 * 获取指定日期的秒.
	 *
	 * @return java.lang.Long
	 */
	public static Long getSecondsByTime(LocalDateTime time) {
		return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
	}

	/**
	 * 获取指定时间的指定格式.
	 *
	 * @return java.lang.String
	 */
	public static String formatTime(LocalDateTime time, String pattern) {
		return time.format(DateTimeFormatter.ofPattern(pattern));
	}

	/**
	 * 获取默认时间的指定格式.(yyyy-MM-dd HH:mm:ss)
	 *
	 * @return java.lang.String
	 */
	public static String formatTime(LocalDateTime time) {
		if(null == time) {
			return null;
		}
		return time.format(LOCAL_DATE_TIME);
	}

	/**
	 * 获取当前时间的指定格式.
	 *
	 * @return java.lang.String
	 */
	public static String formatNow(String pattern) {
		return formatTime(LocalDateTime.now(), pattern);
	}
	
	/**
	 * 获取当前时间的默认格式.(yyyy-MM-dd HH:mm:ss)
	 *
	 * @return java.lang.String
	 */
	public static String formatNow() {
		return formatTime(LocalDateTime.now());
	}

	/**
	 * 获取指定日期的指定格式.
	 *
	 * @return java.lang.String
	 */
	public static String formatDate(LocalDate date, String pattern) {
		return date.format(DateTimeFormatter.ofPattern(pattern));
	}

	/**
	 * 获取指定日期的指定格式.
	 *
	 * @return java.lang.String
	 */
	public static String formatDate(LocalDateTime dateTime, String pattern) {
		return dateTime.format(DateTimeFormatter.ofPattern(pattern));
	}

	/**
	 * 获取默认日期的指定格式.(yyyy-MM-dd)
	 *
	 * @return java.lang.String
	 */
	public static String formatDate(LocalDate date) {
		if(null == date) {
			return null;
		}
		return date.format(LOCAL_DATE);
	}

	/**
	 * 获取默认日期的指定格式.(yyyy-MM-dd)
	 *
	 * @return java.lang.String
	 */
	public static String formatDate(LocalTime date) {
		if(null == date) {
			return "";
		}
		return date.format(LOCAL_TIME);
	}

	/**
	 * 获取默认日期的指定格式.(yyyy-MM-dd)
	 *
	 * @return java.lang.String
	 */
	public static String formatDate(LocalDateTime time) {
		if(null == time) {
			return null;
		}
		return time.format(LOCAL_DATE);
	}

	/**
	 * 获取当前日期的指定格式.
	 *
	 * @return java.lang.String
	 */
	public static String formatDateNow(String pattern) {
		return formatDate(LocalDate.now(), pattern);
	}

	/**
	 * 获取当前日期的默认格式.(yyyy-MM-dd HH:mm:ss)
	 *
	 * @return java.lang.String
	 */
	public static String formatDateNow() {
		return formatDate(LocalDate.now());
	}

	/**
	 * 日期型字符串转化为LocalDateTime
	 * 
	 * @param str
	 *            yyyy-MM-dd HH:mm:ss格式
	 * @return
	 */
	public static LocalDateTime parseDateTime(String str) {
		return LocalDateTime.parse(str, LOCAL_DATE_TIME);
	}
	
	/**
	 * 日期型字符串转化为LocalDateTime
	 * 
	 * @param str
	 * @param pattern
	 * @return
	 */
	public static LocalDateTime parseDateTime(String str, String pattern) {
		return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(pattern));
	}

	/**
	 * 日期型字符串转化为LocalDate
	 * 
	 * @param str
	 *            yyyy-MM-dd格式
	 * @return
	 */
	public static LocalDate parseDate(String str) {
		return LocalDate.parse(str, LOCAL_DATE);
	}

	/**
	 * 日期型字符串转化为LocalDate
	 * 
	 * @param str
	 *            yyyyMMdd格式
	 * @return
	 */
	public static LocalDate parseDateFormat(String str) {
		return LocalDate.parse(str, LOCAL_DATE_FORMAT);
	}
	
    /**
     * 日期型字符串转化为LocalTime
     *
     * @param str HH:mm:ss格式
     * @return
     */
    public static LocalTime parseTime(String str) {
        return LocalTime.parse(str, LOCAL_TIME);
    }

    /**
     * 日期加上一个数,根据field不同加不同值(field参数为ChronoUnit.*)
     *
     * @param time   日期时间
     * @param number 需要加的数
     * @param field  例：ChronoUnit.DAYS(天)
     * @return java.time.LocalDateTime
     */
    public static LocalDateTime plus(LocalDateTime time, long number, TemporalUnit field) {
        return time.plus(number, field);
    }

	/**
	 * 日期减去一个数,根据field不同加不同值(field参数为ChronoUnit.*)
	 * 
	 * @param time
	 *            日期时间
	 * @param number
	 *            需要加的数
	 * @param field
	 *            例：ChronoUnit.DAYS(天)
	 * @return java.time.LocalDateTime
	 */
	public static LocalDateTime minus(LocalDateTime time, long number, TemporalUnit field) {
		return time.minus(number, field);
	}

	/**
	 * 获取两个日期的差(field参数为ChronoUnit.*)
	 * 
	 * @param startTime
	 *            开始日期
	 * @param endTime
	 *            结束日期
	 * @param field
	 *            例：ChronoUnit.DAYS(天)
	 * @return java.time.LocalDateTime
	 */
	public static long betweenTwoTime(LocalDateTime startTime, LocalDateTime endTime, ChronoUnit field) {
		long between = Long.MIN_VALUE;
		switch (field) {
		case YEARS:
			between = ChronoUnit.YEARS.between(startTime, endTime);
			break;
		case MONTHS:
			between = ChronoUnit.MONTHS.between(startTime, endTime);
			break;
		case DAYS:
			between = ChronoUnit.DAYS.between(startTime, endTime);
			break;
		case HOURS:
			between = ChronoUnit.HOURS.between(startTime, endTime);
			break;
		case MINUTES:
			between = ChronoUnit.MINUTES.between(startTime, endTime);
			break;
		case SECONDS:
			between = ChronoUnit.MINUTES.between(startTime, endTime);
			break;
		default:
			break;
		}

		return between;
	}

	/**
	 * 获取一天的开始时间(00:00.)
	 * 
	 * @param time
	 *            日期
	 * @return java.time.LocalDateTime
	 */
	public static LocalDateTime getDayStart(LocalDateTime time) {
		return time.withHour(0).withMinute(0).withSecond(0).withNano(0);
	}

	/**
	 * 获取一天的结束时间(23:59:59.999999999)
	 * 
	 * @param time
	 *            日期
	 * @return java.time.LocalDateTime
	 */
	public static LocalDateTime getDayEnd(LocalDateTime time) {
		return time.withHour(23).withMinute(59).withSecond(59).withNano(999);
	}

	/**
	 * 获取一天的开始时间(00:00:00)
	 * 
	 * @param time
	 *            日期
	 * @return java.time.LocalDateTime
	 */
	public static LocalDateTime getDayStart(LocalDate date) {
		return LocalDateTime.parse(date.toString() + " 00:00:00", LOCAL_DATE_TIME).withNano(0);
	}

	/**
	 * 获取一天的结束时间(23:59:59)
	 * 
	 * @param time
	 *            日期
	 * @return java.time.LocalDateTime
	 */
	public static LocalDateTime getDayEnd(LocalDate date) {
		return LocalDateTime.parse(date.toString() + " 23:59:59", LOCAL_DATE_TIME);
	}

	/**
	 * 日期相减得到天数
	 * 
	 * @param startDateStr
	 *            开始日期(yyyy-MM-dd)
	 * @param endDateStr
	 *            结束日期(yyyy-MM-dd)
	 * @return
	 */
	@Deprecated
	public static long getDaySub(String startDateStr, String endDateStr) {
		long day = 0;

		try {
			SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
			Date beginDate = format.parse(startDateStr);
			Date endDate = format.parse(endDateStr);
			day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return day;
	}

	/**
	 * 日期相减得到天数
	 * 
	 * @param startDate
	 *            开始日期
	 * @param endDate
	 *            结束日期
	 * @return
	 */
	public static long getDaysDiff(LocalDate startDate, LocalDate endDate) {
		LocalDateTime startTime = LocalDateTime.parse(startDate.toString() + " 00:00:00", LOCAL_DATE_TIME);
		LocalDateTime endTime = LocalDateTime.parse(endDate.toString() + " 00:00:00", LOCAL_DATE_TIME);
		return betweenTwoTime(startTime, endTime, ChronoUnit.DAYS);
	}

	/**
	 * 日期相减得到天数
	 * 
	 * @param startDateTime
	 *            开始日期
	 * @param endDateTime
	 *            结束日期
	 * @return
	 */
	public static long getDaysDiff(LocalDateTime startDateTime, LocalDateTime endDateTime) {
		return betweenTwoTime(getDayStart(startDateTime), getDayStart(endDateTime), ChronoUnit.DAYS);
	}

	/**
	 * 日期相减得到天数
	 * 
	 * @param startDateTime
	 *            开始日期
	 * @param endDate
	 *            结束日期
	 * @return
	 */
	public static long getDaysDiff(LocalDateTime startDateTime, LocalDate endDate) {
		return betweenTwoTime(getDayStart(startDateTime),
				LocalDateTime.parse(endDate.toString() + " 00:00:00", LOCAL_DATE_TIME), ChronoUnit.DAYS);
	}

	/**
	 * 日期相减得到天数
	 * 
	 * @param startDate
	 *            开始日期
	 * @param endDateTime
	 *            结束日期
	 * @return
	 */
	public static long getDaysDiff(LocalDate startDate, LocalDateTime endDateTime) {
		return betweenTwoTime(LocalDateTime.parse(startDate.toString() + " 00:00:00", LOCAL_DATE_TIME),
				getDayStart(endDateTime), ChronoUnit.DAYS);
	}

	/**
	 * 获取日期为周几
	 * 
	 * @param date
	 * @return
	 */
	public static String getWeek(LocalDate date) {
		String week = String.valueOf(date.getDayOfWeek());
		//获取行数
		for (int i = 0; i < WEEK_ARRAYS.length; i++) {
			if (week.equals(WEEK_ARRAYS[i][0])) {
				week = WEEK_ARRAYS[i][1];
		       break;
		     }
		}

		return week;
	}

	/**
	 * 获取日期为周几
	 * 
	 * @param date
	 * @return
	 */
	public static String getWeek(LocalDateTime date) {
		return getWeek(date.toLocalDate());
	}


	/**
	 * 获取当前日期的指定格式.
	 *
	 * @return java.lang.String
	 */
	public static String formatLocalDateNow() {
		return LocalDate.now().format(LOCAL_DATE_FORMAT);
	}
	
	/**
	 * 返回n天后的某天
	 * @param n 为正数时是当前时间的n天后的某天
	 *          为负数时是当前时间的n天前的某天
	 * @return
	 */
	public static LocalDateTime getNDays(int n){
	    Calendar calendar = Calendar.getInstance();
	    calendar.setTime(new Date());
	    calendar.add(Calendar.DATE,n);
	    return convertDateToLDT(calendar.getTime());
	} 

	/**
	 * 获取传入日期的月付的开始一天日期
	 * 
	 * @param dateTime
	 * @return
	 */
	public static LocalDateTime firstDayOfMonth(LocalDateTime dateTime) {
		return dateTime.with(TemporalAdjusters.firstDayOfMonth());
	}

	/**
	 * 获取传入日期的月付的最后一天日期
	 * 
	 * @param dateTime
	 * @return
	 */
	public static LocalDateTime lastDayOfMonth(LocalDateTime dateTime) {
		return dateTime.with(TemporalAdjusters.lastDayOfMonth());
	}

	/**
	 * 获取传入日期的月付的开始一天日期
	 * 
	 * @param dateTime
	 * @return
	 */
	public static LocalDate firstDayOfMonth(LocalDate date) {
		return date.with(TemporalAdjusters.firstDayOfMonth());
	}

	/**
	 * 获取传入日期的月付的最后一天日期
	 * 
	 * @param dateTime
	 * @return
	 */
	public static LocalDate lastDayOfMonth(LocalDate date) {
		return date.with(TemporalAdjusters.lastDayOfMonth());
	}

	/**
	 * 根据传入时间获取上周四的日期
	 *
	 * @param date
	 * @return
	 */
	public static String getViolationStatisticsTimeStr(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);

		// 获得当前日期是一个星期的第几天
		int dayWeek = cal.get(Calendar.DAY_OF_WEEK);

		//星期四、五、六直接取
		if (5 == dayWeek || 6 == dayWeek || 7 == dayWeek) {
			cal.set(Calendar.DAY_OF_WEEK,5);
		}else{
			cal.set(Calendar.DAY_OF_WEEK,5);
			cal.add(Calendar.DATE, -7);
		}

		return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
	}

}
